﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

namespace EcoSystem
{
    /// <summary>
    /// 添加迁移注释扩展类
    /// 迁移文件实体配置示例如下：
    /// <code>
    /// builder.Entity<Simple>(b =>
    /// {
    ///     b.ToTable(options.TablePrefix + "Simple", options.Schema);
    ///     b.ConfigureFullAuditedAggregateRoot();
    ///     b.CreateComment();  //给实体添加注释迁移代码
    /// });
    /// </code>
    /// </summary>
    public static class DbContextModelCreateCommentExtensions
    {
        /// <summary>
        /// 实体Domain文件
        /// </summary>
        private static string domainXmlFile = "EcoSystem.Domain.xml";

        /// <summary>
        /// 系统字段处理
        /// </summary>
        private static Dictionary<string, string> systemFields = new Dictionary<string, string>() {
            { "Id", "主键ID" },
            { "ExtraProperties", "扩展属性" },
            { "ConcurrencyStamp", "并发处理时间戳" },
            { "CreationTime", "创建时间" },
            { "CreatorId", "创建人ID" },
            { "LastModificationTime", "最后修改时间" },
            { "LastModifierId", "最后修改人ID" },
            { "IsDeleted", "是否删除" },
            { "DeleterId", "删除人ID" },
            { "DeletionTime", "删除时间" },
        };

        /// <summary>
        /// 给实体添加注释迁移代码
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="b"></param>
        public static void CreateComment<TEntity>(this EntityTypeBuilder<TEntity> b) where TEntity : class
        {
            var path = Path.Combine(AppContext.BaseDirectory, domainXmlFile);
            XmlDocument xml = new();
            xml.Load(path);
            XmlNodeList memebers = xml.SelectNodes("/doc/members/member")!;
            b.ToTable(t => t.HasComment(GetEntityComment(memebers, b.Metadata.Name)));
            List<string> baseTypeNames = new();
            var baseType = b.Metadata.ClrType.BaseType;
            while (baseType != null)
            {
                baseTypeNames.Add(baseType.FullName!);
                baseType = baseType.BaseType;
            }

            foreach (var property in b.Metadata.GetProperties())
            {
                //设置字段的备注
                if (systemFields.ContainsKey(property.Name))
                {
                    property.SetComment(systemFields[property.Name]);
                }
                else
                {
                    property.SetComment(GetEntityComment(memebers, b.Metadata.Name, property.Name, baseTypeNames));
                }
            }
        }

        /// <summary>
        /// 获取实体指定字段注释信息
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="fieldName"></param>
        /// <param name="baseTypeNames"></param>
        /// <returns></returns>
        public static string GetEntityComment(XmlNodeList memebers, string typeName, string fieldName = null, List<string> baseTypeNames = null)
        {
            Dictionary<string, string> fieldList = new();

            if (fieldName == null)
            {
                var matchKey = "T:" + typeName;

                foreach (object m in memebers)
                {
                    if (m is XmlNode node)
                    {
                        var name = node.Attributes!["name"]!.Value;

                        var summary = node.InnerText.Trim();

                        if (name == matchKey)
                        {
                            fieldList.Add(name, summary);
                        }
                    }
                }

                var comment = fieldList.FirstOrDefault(t => t.Key.ToLower() == matchKey.ToLower()).Value ?? typeName.ToString().Split(".").ToList().LastOrDefault()!;
                return comment?.Replace("\r", "").Replace("\n", "");
            }
            else
            {

                foreach (object m in memebers)
                {
                    if (m is XmlNode node)
                    {
                        string name = node.Attributes!["name"]!.Value;

                        var summary = node.InnerText.Trim();

                        var matchKey = "P:" + typeName + ".";
                        if (name.StartsWith(matchKey))
                        {
                            name = name.Replace(matchKey, "");

                            fieldList.Remove(name);

                            fieldList.Add(name, summary);
                        }

                        if (baseTypeNames != null)
                        {
                            foreach (var baseTypeName in baseTypeNames)
                            {
                                if (baseTypeName != null)
                                {
                                    matchKey = "P:" + baseTypeName + ".";
                                    if (name.StartsWith(matchKey))
                                    {
                                        name = name.Replace(matchKey, "");
                                        fieldList.Add(name, summary);
                                    }
                                }
                            }
                        }
                    }
                }
                var comment = fieldList.FirstOrDefault(t => t.Key.ToLower() == fieldName.ToLower()).Value ?? fieldName;
                return comment?.Replace("\r", "").Replace("\n", "");
            }
        }

    }
}